package cn.edu.sjtu.se.dslab.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import org.apache.log4j.Logger;

/** 
 * @ClassName: PackUtil
 * @Description: the tool for package file
 * @author longshaohang
 * @date 2013-7-19 上午9:04:35
 * 
 */ 
public class PackUtil {
	private static final Logger logger = Logger.getLogger(PackUtil.class);
	
	private static final String GBK = "gbk";
	private static final String UTF8 = "utf-8";
	
	private static final int BUFFER_SIZE = 1024 * 10;
	
	/**
	 * 把源目录sourceDirPath下的所有文件及目录打包到zipFilePath下，打包的文件名字为zipFileName
	 * @param sourceDirPath: the absolute path of source directory
	 * @param zipFilePath: the absolute path to put the zip file 
	 * @param zipFileName: the zip file name
	 * @return 
	 * @throws IOException 
	 */
	public static boolean zip(String sourceDirPath, String zipFilePath, String zipFileName) throws IOException{
		


		StringBuffer srcDirPath = new StringBuffer(sourceDirPath);
		//make it the right source directory path
		if ( sourceDirPath.charAt(sourceDirPath.length() -1 ) != '/'){
			srcDirPath.append('/');
			System.out.println("src:" + srcDirPath.toString());
		}
		
		File sourceFile = new File(srcDirPath.toString());
		boolean isSuccess = false;
		if (!sourceFile.exists()) {
			System.out.println("The directory :" + sourceDirPath + " is not exist!");
			return isSuccess;
		}

		StringBuffer zipDirPath = new StringBuffer(zipFilePath);
		if ( zipFilePath.charAt(zipFilePath.length() -1 ) != '/'){
			zipDirPath.append('/');
			System.out.println("tag:" + zipDirPath.toString());
		}

		File zipDir = new File(zipDirPath.toString());
		if (!zipDir.exists()){
			System.out.println("create target directorys :" + zipDirPath);
			zipDir.mkdirs();
		}

		//StringBuffer sb = new StringBuffer();
		//sb.append(zipFilePath).append("/").append(zipFileName);
		File zipFile = new File(zipDirPath.append(zipFileName).toString());
		if (zipFile.exists()){
			System.out.println("The zip file :" + zipDirPath.toString() + " has existed!");
			System.out.println("delete it!");
			zipFile.deleteOnExit();
		}

		ZipOutputStream zos = null;
		try {
			zipFile.createNewFile();
			zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));

			logger.info("packing....");
			doZip1(zos,sourceFile.listFiles(),"");
			isSuccess = true;

		} //catch (FileNotFoundException e) {
		//	e.printStackTrace();
		//} catch (IOException e) {
		//	e.printStackTrace();
		//}
		finally{
			if (null != zos) {
				try{
					zos.flush();
					zos.close();
				}catch(IOException ioe){
					ioe.printStackTrace();
					throw new RuntimeException(ioe);  
				}
			}

		}
		return isSuccess;
	}

	/**
	* @Title: zipList
	* @Description: 把sourceFilePathList中的所有文件打包到zipFilePath下，打包的文件名字为zipFileName
	* @param sourcefilePathList
	* @param zipFilePath
	* @param zipFileName
	* @throws IOException
	* @return boolean
	 */
	public static boolean zipList(List<String> sourcefilePathList, String zipFilePath, String zipFileName) throws IOException{
		boolean isSuccess = false;
		
		StringBuffer zipDirPath = new StringBuffer(zipFilePath);
		//make it the right source directory path
		if ( zipFilePath.charAt(zipFilePath.length() -1 ) != '/'){
			zipDirPath.append('/');
			System.out.println("tag:" + zipDirPath.toString());
		}

		File zipDir = new File(zipDirPath.toString());
		if (!zipDir.exists()){
			System.out.println("create target directorys :" + zipDirPath);
			zipDir.mkdirs();
		}

		File zipFile = new File(zipDirPath.append(zipFileName).toString());
		if (zipFile.exists()){
			System.out.println("The zip file :" + zipDirPath.toString() + " has existed!");
			System.out.println("delete it!");
			zipFile.deleteOnExit();
		}
		
		ZipOutputStream zos = null;
		try {
			zipFile.createNewFile();
			zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
			logger.info("Packing file...");
			for (String filePath: sourcefilePathList){
				File sourceFile = new File(filePath);
				if (!sourceFile.exists()) {
					logger.error("The directory :" + filePath + " is not exist!");
					return false;
				}
				doZip(zos,sourceFile,"");
			}
			isSuccess = true;
		}// catch (FileNotFoundException e) {
		//	e.printStackTrace();
		//} catch (IOException e) {
		//	e.printStackTrace();
		//}
		finally{
			if (null != zos) {
				try{
					zos.flush();
					zos.close();
				}catch(IOException ioe){
					ioe.printStackTrace();
					throw new RuntimeException(ioe);  
				}
			}
		}
		return isSuccess;

	}
	
	/**
	 * 
	* @Title: doZip
	* @Description: 把File打包到ZipOutputStream这个流中，如果file是目录，则递归调用
	* @param zos
	* @param file
	* @param basePath
	* @throws IOException
	* @return void
	* @throws
	 */
	private static void doZip(ZipOutputStream zos, File file, String basePath) throws IOException{
		if (file.isDirectory()){
			File[] fileList = file.listFiles();
			zos.putNextEntry(new ZipEntry(basePath + file.getName() + "/"));
			System.out.println("Dir entry=======:" + basePath + file.getName() + "/");
			for (File f: fileList){
				doZip(zos, f, basePath + file.getName() + "/");
			}
		}else {
			zos.putNextEntry(new ZipEntry(basePath + file.getName()) );
			logger.info("file entry:" + basePath + file.getName());
			byte buffer[] = new byte[BUFFER_SIZE];
			BufferedInputStream bis = new BufferedInputStream( new FileInputStream(file), BUFFER_SIZE);
			int flag = 0;
			while( (flag = bis.read(buffer, 0, BUFFER_SIZE))!= -1){
//				String temp = new String(buffer, UTF8);   //将buffer解析成utf-8编码
//				zos.write(temp.getBytes(GBK),0,flag);  //将temp变成以gbk编码的数组
				zos.write(buffer,0,flag);  //将temp变成以gbk编码的数组
			}
			bis.close();
		}
	}
	//只把fileList所对应的打包，
	private static void doZip1(ZipOutputStream zos, File[] fileList,
			String basePath) throws IOException {
		for (File file : fileList) {
			if (file.isDirectory()) {
				logger.info("directory entry: " + basePath + file.getName() + "/");
				zos.putNextEntry(new ZipEntry(basePath + file.getName() + "/")); 
				//for (File f : file.listFiles()) {
					doZip1(zos, file.listFiles(), basePath + file.getName() + "/");
				//}
			} else {
				zos.putNextEntry(new ZipEntry(basePath + file.getName()));
				logger.info("file entry:" + basePath + file.getName());
				byte buffer[] = new byte[BUFFER_SIZE];
				BufferedInputStream bis = new BufferedInputStream(
						new FileInputStream(file), BUFFER_SIZE);
				int flag = 0;
				while ((flag = bis.read(buffer, 0, BUFFER_SIZE)) != -1) {
					// String temp = new String(buffer, UTF8);
					// //将buffer解析成utf-8编码
					// zos.write(temp.getBytes(GBK),0,flag); //将temp变成以gbk编码的数组
					zos.write(buffer, 0, flag); // 将temp变成以gbk编码的数组
				}
				bis.close();
			}
		}
	}
	
	/**
	* @Title: unzip
	* @Description: 把zip文件解压到targetDirPath这个目录下
	* @param zipFilePath
	* @param targetDirPath
	* @throws IOException
	* @return boolean
	 */
	public static boolean unzip(String zipFilePath, String targetDirPath) throws IOException{
		File file = new File(zipFilePath);
		boolean isSuccess = false;
		if (!file.exists()){
			System.out.println("the zip file : " + zipFilePath + " is not exist!");
			return false;
		}
		if (!file.isFile()){
			System.out.println(zipFilePath + " is not a file!");
			return false;
		}
		StringBuffer zipFileDir = new StringBuffer(targetDirPath);
		//make it the right file path
		if ( targetDirPath.charAt(targetDirPath.length() -1 ) != '/'){
			zipFileDir.append('/');
		}
		//add the directory to the target directory path
		//the directory name is the same as the zip file name
		int pointIndex = file.getName().lastIndexOf('.');
		zipFileDir.append(file.getName().substring(0, pointIndex)).append('/');
		File targetDir = new File(zipFileDir.toString());

		if (!targetDir.exists()){
			targetDir.mkdirs();
		}
		ZipFile zipFile = null;

		try {
			zipFile = new ZipFile(file);
			Enumeration<? extends ZipEntry> entrys = zipFile.entries();
			while(entrys.hasMoreElements()){
				ZipEntry zipEntry = entrys.nextElement();
				if (zipEntry.isDirectory()){
					String name = zipEntry.getName();
					File dir = new File(zipFileDir.toString() + name);
					logger.info("Unzip dir: " + name);
					dir.mkdirs();
				}else{
					File f = new File(zipFileDir.toString() + zipEntry.getName());
					logger.info("Unzip file: " + zipEntry.getName());
					f.createNewFile();
					InputStream is = zipFile.getInputStream(zipEntry);
					//					BufferedInputStream bis = new BufferedInputStream(is);
					FileOutputStream fos = new FileOutputStream(f);
					byte buffer[] = new byte[BUFFER_SIZE];
					int flag;
					while((flag = is.read(buffer, 0, BUFFER_SIZE))!= -1){
						fos.write(buffer, 0, flag);
					}
					is.close();
					fos.flush();
					fos.close();
				}
			}
			isSuccess = true;
		}
		//catch (ZipException e) {
			//e.printStackTrace();
		//} catch (IOException e) {
		//	e.printStackTrace();
		//}
		finally{
			if (null != zipFile){
				try {
					zipFile.close();
				} catch (IOException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				}
			}
		}
		return isSuccess;
	}
}
